home *** CD-ROM | disk | FTP | other *** search
/ Maclife 157 / MACLIFE157-2001-09.ISO.7z / MACLIFE157-2001-09.ISO / Linux / MacOS Tools / Other / BootX 1.1.3 (for Old Mac OS) / Sources / lib / From MoreFiles / MoreDesktopMgr.c < prev    next >
Text File  |  2001-07-23  |  33KB  |  1,255 lines

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    A collection of useful high-level Desktop Manager routines.
  5. **    If the Desktop Manager isn't available, use the Desktop file
  6. **    for 'read' operations.
  7. **
  8. **    We do more because we can...
  9. **
  10. **    by Jim Luther and Nitin Ganatra, Apple Developer Technical Support Emeriti
  11. **
  12. **    File:    MoreDesktopMgr.c
  13. **
  14. **    Copyright ゥ 1992-1998 Apple Computer, Inc.
  15. **    All rights reserved.
  16. **
  17. **    You may incorporate this sample code into your applications without
  18. **    restriction, though the sample code has been provided "AS IS" and the
  19. **    responsibility for its operation is 100% yours.  However, what you are
  20. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  21. **    after having made changes. If you're going to re-distribute the source,
  22. **    we require that you make it clear in the source that the code was
  23. **    descended from Apple Sample Code, but that you've made changes.
  24. */
  25.  
  26. #include <Types.h>
  27. #include <Errors.h>
  28. #include <Memory.h>
  29. #include <Files.h>
  30. #include <Resources.h>
  31. #include <Icons.h>
  32.  
  33. #define    __COMPILINGMOREFILES
  34.  
  35. #include "MoreFiles.h"
  36. #include "MoreFilesExtras.h"
  37. #include "Search.h"
  38. #include "MoreDesktopMgr.h"
  39.  
  40. /*****************************************************************************/
  41.  
  42. /*    Desktop file notes:
  43. **
  44. **    ・    The Desktop file is owned by the Finder and is normally open by the
  45. **        Finder. That means that we only have read-only access to the Desktop
  46. **        file.
  47. **    ・    Since the Resource Manager doesn't support shared access to resource
  48. **        files and we're using read-only access, we don't ever leave the
  49. **        Desktop file open.  We open a path to it, get the data we want out
  50. **        of it, and then close the open path. This is the only safe way to
  51. **        open a resource file with read-only access since some other program
  52. **        could have it open with write access.
  53. **    ・    The bundle related resources in the Desktop file are normally
  54. **        purgable, so when we're looking through them, we don't bother to
  55. **        release resources we're done looking at - closing the resource file
  56. **        (which we always do) will release them.
  57. **    ・    Since we can't assume the Desktop file is named "Desktop"
  58. **        (it probably is everywhere but France), we get the Desktop
  59. **        file's name by searching the volume's root directory for a file
  60. **        with fileType == 'FNDR' and creator == 'ERIK'. The only problem with
  61. **        this scheme is that someone could create another file with that type
  62. **        and creator in the root directory and we'd find the wrong file.
  63. **        The chances of this are very slim.
  64. */
  65.  
  66. /*****************************************************************************/
  67.  
  68. /* local defines */
  69.  
  70. enum
  71. {
  72.     kBNDLResType    = 'BNDL',
  73.     kFREFResType    = 'FREF',
  74.     kIconFamResType    = 'ICN#',
  75.     kFCMTResType    = 'FCMT',
  76.     kAPPLResType    = 'APPL'
  77. };
  78.  
  79. /*****************************************************************************/
  80.  
  81. /* local data structures */
  82.  
  83. #if PRAGMA_ALIGN_SUPPORTED
  84. #pragma options align=mac68k
  85. #endif
  86.  
  87. struct IDRec
  88. {
  89.     short        localID;
  90.     short        rsrcID;
  91. };
  92. typedef struct IDRec IDRec;
  93. typedef    IDRec *IDRecPtr;
  94.  
  95. struct BundleType
  96. {
  97.     OSType        type;            /* 'ICN#' or 'FREF' */
  98.     short        count;            /* number of IDRecs - 1 */
  99.     IDRec        idArray[1];
  100. };
  101. typedef struct BundleType BundleType;
  102. typedef BundleType *BundleTypePtr;
  103.  
  104. struct BNDLRec
  105. {
  106.     OSType        signature;        /* creator type signature */
  107.     short        versionID;        /* version - should always be 0 */
  108.     short        numTypes;        /* number of elements in typeArray - 1 */
  109.     BundleType    typeArray[1];
  110. };
  111. typedef struct BNDLRec BNDLRec;
  112. typedef BNDLRec **BNDLRecHandle;
  113.  
  114. struct FREFRec
  115. {
  116.     OSType        fileType;        /* file type */
  117.     short        iconID;            /* icon local ID */
  118.     Str255        fileName;        /* file name */
  119. };
  120. typedef struct FREFRec FREFRec;
  121. typedef FREFRec **FREFRecHandle;
  122.  
  123. struct APPLRec
  124. {
  125.     OSType        creator;        /* creator type signature */
  126.     long        parID;            /* parent directory ID */
  127.     Str255        applName;        /* application name */
  128. };
  129. typedef struct APPLRec APPLRec;
  130. typedef APPLRec *APPLRecPtr;
  131.  
  132. #if PRAGMA_ALIGN_SUPPORTED
  133. #pragma options align=reset
  134. #endif
  135.  
  136. /*****************************************************************************/
  137.  
  138. /* static prototypes */
  139.  
  140. static    OSErr    GetDesktopFileName(short vRefNum,
  141.                                    Str255 desktopName);
  142.  
  143. static    OSErr    GetAPPLFromDesktopFile(ConstStr255Param volName,
  144.                                        short vRefNum,
  145.                                        OSType creator,
  146.                                        short *applVRefNum,
  147.                                        long *applParID,
  148.                                        Str255 applName);
  149.  
  150. static    OSErr    FindBundleGivenCreator(OSType creator,
  151.                                        BNDLRecHandle *returnBndl);
  152.                                        
  153. static    OSErr    FindTypeInBundle(OSType typeToFind,
  154.                                  BNDLRecHandle theBndl,
  155.                                  BundleTypePtr *returnBundleType);
  156.                                          
  157. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  158.                                    OSType fileType,
  159.                                    short *iconLocalID);
  160.  
  161. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  162.                                          short iconLocalID,
  163.                                          short *iconRsrcID);
  164.  
  165. static    OSType    DTIconToResIcon(short iconType);
  166.  
  167. static    OSErr    GetIconFromDesktopFile(ConstStr255Param volName,
  168.                                        short vRefNum,
  169.                                        short iconType,
  170.                                        OSType fileCreator,
  171.                                        OSType fileType,
  172.                                        Handle *iconHandle);
  173.  
  174. static    OSErr    GetCommentID(short vRefNum,
  175.                              long dirID,
  176.                              ConstStr255Param name,
  177.                              short *commentID);
  178.  
  179. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  180.                                           long dirID,
  181.                                           ConstStr255Param name,
  182.                                           Str255 comment);
  183.  
  184. /*****************************************************************************/
  185.  
  186. /*
  187. **    GetDesktopFileName
  188. **
  189. **    Get the name of the Desktop file.
  190. */
  191. static    OSErr    GetDesktopFileName(short vRefNum,
  192.                                    Str255 desktopName)
  193. {
  194.     OSErr            error;
  195.     HParamBlockRec    pb;
  196.     short            index;
  197.     Boolean            found;
  198.     
  199.     pb.fileParam.ioNamePtr = desktopName;
  200.     pb.fileParam.ioVRefNum = vRefNum;
  201.     pb.fileParam.ioFVersNum = 0;
  202.     index = 1;
  203.     found = false;
  204.     do
  205.     {
  206.         pb.fileParam.ioDirID = fsRtDirID;
  207.         pb.fileParam.ioFDirIndex = index;
  208.         error = PBHGetFInfoSync(&pb);
  209.         if ( error == noErr )
  210.         {
  211.             if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
  212.                  (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
  213.             {
  214.                 found = true;
  215.             }
  216.         }
  217.         ++index;
  218.     } while ( (error == noErr) && !found );
  219.     
  220.     return ( error );
  221. }
  222.  
  223. /*****************************************************************************/
  224.  
  225. pascal    OSErr    DTOpen(ConstStr255Param volName,
  226.                        short vRefNum,
  227.                        short *dtRefNum,
  228.                        Boolean *newDTDatabase)
  229. {
  230.     OSErr error;
  231.     GetVolParmsInfoBuffer volParmsInfo;
  232.     long infoSize;
  233.     DTPBRec pb;
  234.     
  235.     /* Check for volume Desktop Manager support before calling */
  236.     infoSize = sizeof(GetVolParmsInfoBuffer);
  237.     error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
  238.     if ( error == noErr )
  239.     {
  240.         if ( hasDesktopMgr(volParmsInfo) )
  241.         {
  242.             pb.ioNamePtr = (StringPtr)volName;
  243.             pb.ioVRefNum = vRefNum;
  244.             error = PBDTOpenInform(&pb);
  245.             /* PBDTOpenInform informs us if the desktop was just created */
  246.             /* by leaving the low bit of ioTagInfo clear (0) */
  247.             *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
  248.             if ( error == paramErr )
  249.             {
  250.                 error = PBDTGetPath(&pb);
  251.                 /* PBDTGetPath doesn't tell us if the database is new */
  252.                 /* so assume it is not new */
  253.                 *newDTDatabase = false;
  254.             }
  255.             *dtRefNum = pb.ioDTRefNum;
  256.         }
  257.         else
  258.         {
  259.             error = paramErr;
  260.         }
  261.     }
  262.     return ( error );
  263. }
  264.  
  265. /*****************************************************************************/
  266.  
  267. /*
  268. **    GetAPPLFromDesktopFile
  269. **
  270. **    Get a application's location from the
  271. **    Desktop file's 'APPL' resources.
  272. */
  273. static    OSErr    GetAPPLFromDesktopFile(ConstStr255Param volName,
  274.                                        short vRefNum,
  275.                                        OSType creator,
  276.                                        short *applVRefNum,
  277.                                        long *applParID,
  278.                                        Str255 applName)
  279. {
  280.     OSErr error;
  281.     short realVRefNum;
  282.     Str255 desktopName;
  283.     short savedResFile;
  284.     short dfRefNum;
  285.     Handle applResHandle;
  286.     Boolean foundCreator;
  287.     Ptr applPtr;
  288.     long applSize;
  289.     
  290.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  291.     if ( error == noErr )
  292.     {
  293.         error = GetDesktopFileName(realVRefNum, desktopName);
  294.         if ( error == noErr )
  295.         {
  296.             savedResFile = CurResFile();
  297.             /*
  298.             **    Open the 'Desktop' file in the root directory. (because
  299.             **    opening the resource file could preload unwanted resources,
  300.             **    bracket the call with SetResLoad(s))
  301.             */
  302.             SetResLoad(false);
  303.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  304.             SetResLoad(true);
  305.             
  306.             if ( dfRefNum != -1)
  307.             {
  308.                 /* Get 'APPL' resource ID 0 */
  309.                 applResHandle = Get1Resource(kAPPLResType, 0);
  310.                 if ( applResHandle != NULL )
  311.                 {
  312.                     applSize = InlineGetHandleSize((Handle)applResHandle);
  313.                     if ( applSize != 0 )    /* make sure the APPL resource isn't empty */
  314.                     {
  315.                         foundCreator = false;
  316.                         applPtr = *applResHandle;
  317.                         
  318.                         /* APPL's don't have a count so I have to use the size as the bounds */
  319.                         while ( (foundCreator == false) &&
  320.                                 (applPtr < (*applResHandle + applSize)) )
  321.                         {
  322.                             if ( ((APPLRecPtr)applPtr)->creator == creator )
  323.                             {
  324.                                 foundCreator = true;
  325.                             }
  326.                             else
  327.                             {
  328.                                 /* fun with pointer math... */
  329.                                 applPtr += sizeof(OSType) +
  330.                                            sizeof(long) +
  331.                                            ((APPLRecPtr)applPtr)->applName[0] + 1;
  332.                                 /* application mappings are word aligned within the resource */
  333.                                 if ( ((unsigned long)applPtr % 2) != 0 )
  334.                                 {
  335.                                     applPtr += 1;
  336.                                 }
  337.                             }
  338.                         }
  339.                         if ( foundCreator == true )
  340.                         {
  341.                             *applVRefNum = realVRefNum;
  342.                             *applParID = ((APPLRecPtr)applPtr)->parID;
  343.                             BlockMoveData(((APPLRecPtr)applPtr)->applName,
  344.                                           applName,
  345.                                           ((APPLRecPtr)applPtr)->applName[0] + 1);
  346.                             /* error is already noErr */
  347.                         }
  348.                         else
  349.                         {
  350.                             error = afpItemNotFound;    /* didn't find a creator match */
  351.                         }
  352.                     }
  353.                     else
  354.                     {
  355.                         error = afpItemNotFound;    /* no APPL mapping available */
  356.                     }
  357.                 }
  358.                 else
  359.                 {
  360.                     error = afpItemNotFound;    /* no APPL mapping available */
  361.                 }
  362.                 
  363.                 /* restore the resource chain and close the Desktop file */
  364.                 UseResFile(savedResFile);
  365.                 CloseResFile(dfRefNum);
  366.             }
  367.             else
  368.             {
  369.                 error = afpItemNotFound;
  370.             }
  371.         }
  372.     }
  373.     
  374.     return ( error );
  375. }
  376.  
  377. /*****************************************************************************/
  378.  
  379. pascal    OSErr    DTXGetAPPL(ConstStr255Param volName,
  380.                            short vRefNum,
  381.                            OSType creator,
  382.                            Boolean searchCatalog,
  383.                            short *applVRefNum,
  384.                            long *applParID,
  385.                            Str255 applName)
  386. {
  387.     OSErr error;
  388.     UniversalFMPB pb;
  389.     short dtRefNum;
  390.     Boolean newDTDatabase;
  391.     short realVRefNum;
  392.     short index;
  393.     Boolean applFound;
  394.     FSSpec spec;
  395.     long actMatchCount;
  396.     
  397.     /* get the real vRefNum */
  398.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  399.     if ( error == noErr )
  400.     {
  401.         error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  402.         if ( error == noErr )
  403.         {
  404.             if ( !newDTDatabase )
  405.             {
  406.                 index = 0;
  407.                 applFound = false;
  408.                 do
  409.                 {
  410.                     pb.dtPB.ioNamePtr = applName;
  411.                     pb.dtPB.ioDTRefNum = dtRefNum;
  412.                     pb.dtPB.ioIndex = index;
  413.                     pb.dtPB.ioFileCreator = creator;
  414.                     error = PBDTGetAPPLSync(&pb.dtPB);
  415.                     if ( error == noErr )
  416.                     {
  417.                         /* got a match - see if it is valid */
  418.                         
  419.                         *applVRefNum = realVRefNum; /* get the vRefNum now */
  420.                         *applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */
  421.     
  422.                         /* pb.hPB.fileParam.ioNamePtr is already set */
  423.                         pb.hPB.fileParam.ioVRefNum = realVRefNum;
  424.                         pb.hPB.fileParam.ioFVersNum = 0;
  425.                         pb.hPB.fileParam.ioDirID = *applParID;
  426.                         pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  427.                         if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  428.                         {
  429.                             if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) &&
  430.                                  (pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') )
  431.                             {
  432.                                 applFound = true;
  433.                             }
  434.                         }
  435.                     }
  436.                     ++index;
  437.                 } while ( (error == noErr) && !applFound );
  438.                 if ( error != noErr )
  439.                 {
  440.                     error = afpItemNotFound;
  441.                 }
  442.             }
  443.             else
  444.             {
  445.                 /* Desktop database is empty (new), set error to try CatSearch */
  446.                 error = afpItemNotFound;
  447.             }
  448.         }
  449.         /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */
  450.         if ( error == paramErr )
  451.         {
  452.             /* if paramErr, the volume didn't support the Desktop Manager */
  453.             /* try the Desktop file */
  454.             
  455.             error = GetAPPLFromDesktopFile(volName, vRefNum, creator,
  456.                                             applVRefNum, applParID, applName);
  457.             if ( error == noErr )
  458.             {
  459.                 /* got a match - see if it is valid */
  460.                 
  461.                 pb.hPB.fileParam.ioNamePtr = applName;
  462.                 pb.hPB.fileParam.ioVRefNum = *applVRefNum;
  463.                 pb.hPB.fileParam.ioFVersNum = 0;
  464.                 pb.hPB.fileParam.ioDirID = *applParID;
  465.                 pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  466.                 if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  467.                 {
  468.                     if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) ||
  469.                          (pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') )
  470.                     {
  471.                         error = afpItemNotFound;
  472.                     }
  473.                 }
  474.                 else if ( error == fnfErr )
  475.                 {
  476.                     error = afpItemNotFound;
  477.                 }
  478.             }
  479.         }
  480.         /* acceptable error from DesktopFile code to continue is afpItemNotFound */
  481.         if ( (error == afpItemNotFound) && searchCatalog)
  482.         {
  483.             /* Couldn't be found in the Desktop file either, */
  484.             /* try searching with CatSearch if requested */
  485.             
  486.             error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1,
  487.                                             &actMatchCount, true);
  488.             if ( (error == noErr) || (error == eofErr) )
  489.             {
  490.                 if ( actMatchCount > 0 )
  491.                 {
  492.                     *applVRefNum = spec.vRefNum;
  493.                     *applParID = spec.parID;
  494.                     BlockMoveData(spec.name, applName, spec.name[0] + 1);
  495.                 }
  496.                 else
  497.                 {
  498.                     error = afpItemNotFound;
  499.                 }
  500.             }
  501.         }
  502.     }
  503.     
  504.     return ( error );
  505. }
  506.  
  507. /*****************************************************************************/
  508.  
  509. pascal    OSErr    FSpDTXGetAPPL(ConstStr255Param volName,
  510.                               short vRefNum,
  511.                               OSType creator,
  512.                               Boolean searchCatalog,
  513.                               FSSpec *spec)
  514. {
  515.     return ( DTXGetAPPL(volName, vRefNum, creator, searchCatalog,
  516.                         &(spec->vRefNum), &(spec->parID), spec->name) );
  517. }
  518.  
  519. /*****************************************************************************/
  520.  
  521. pascal    OSErr    DTGetAPPL(ConstStr255Param volName,
  522.                           short vRefNum,
  523.                           OSType creator,
  524.                           short *applVRefNum,
  525.                           long *applParID,
  526.                           Str255 applName)
  527. {
  528.     /* Call DTXGetAPPL with the "searchCatalog" parameter true */ 
  529.     return ( DTXGetAPPL(volName, vRefNum, creator, true,
  530.                         applVRefNum, applParID, applName) );
  531. }
  532.  
  533. /*****************************************************************************/
  534.  
  535. pascal    OSErr    FSpDTGetAPPL(ConstStr255Param volName,
  536.                              short vRefNum,
  537.                              OSType creator,
  538.                              FSSpec *spec)
  539. {
  540.     /* Call DTXGetAPPL with the "searchCatalog" parameter true */ 
  541.     return ( DTXGetAPPL(volName, vRefNum, creator, true,
  542.                         &(spec->vRefNum), &(spec->parID), spec->name) );
  543. }
  544.  
  545. /*****************************************************************************/
  546.  
  547. /*
  548. **    FindBundleGivenCreator
  549. **
  550. **    Search the current resource file for the 'BNDL' resource with the given
  551. **    creator and return a handle to it.
  552. */
  553. static    OSErr    FindBundleGivenCreator(OSType creator,
  554.                                        BNDLRecHandle *returnBndl)
  555. {
  556.     OSErr            error;
  557.     short            numOfBundles;
  558.     short            index;
  559.     BNDLRecHandle    theBndl;
  560.     
  561.     error = afpItemNotFound;    /* default to not found */
  562.     
  563.     /* Search each BNDL resource until we find the one with a matching creator. */
  564.     
  565.     numOfBundles = Count1Resources(kBNDLResType);
  566.     index = 1;
  567.     *returnBndl = NULL;
  568.     
  569.     while ( (index <= numOfBundles) && (*returnBndl == NULL) )
  570.     {
  571.         theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index);
  572.         
  573.         if ( theBndl != NULL )
  574.         {
  575.             if ( (*theBndl)->signature == creator )
  576.             {
  577.                 /* numTypes and typeArray->count will always be the actual count minus 1, */
  578.                 /* so 0 in both fields is valid. */
  579.                 if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) )
  580.                 {
  581.                     /* got it */
  582.                     *returnBndl = theBndl;
  583.                     error = noErr;
  584.                 }
  585.             }
  586.         }    
  587.         
  588.         index ++;
  589.     }
  590.     
  591.     return ( error );
  592. }
  593.  
  594. /*****************************************************************************/
  595.  
  596. /*
  597. **    FindTypeInBundle
  598. **
  599. **    Given a Handle to a BNDL return a pointer to the desired type
  600. **    in it. If the type is not found, or if the type's count < 0,
  601. **    return afpItemNotFound.
  602. */
  603. static    OSErr    FindTypeInBundle(OSType typeToFind,
  604.                                  BNDLRecHandle theBndl,
  605.                                  BundleTypePtr *returnBundleType)
  606. {
  607.     OSErr            error;
  608.     short            index;
  609.     Ptr                ptrIterator;    /* use a Ptr so we can do ugly pointer math */
  610.     
  611.     error = afpItemNotFound;    /* default to not found */
  612.     
  613.     ptrIterator = (Ptr)((*theBndl)->typeArray);
  614.     index = 0;
  615.     *returnBundleType = NULL;
  616.  
  617.     while ( (index < ((*theBndl)->numTypes + 1)) &&
  618.             (*returnBundleType == NULL) )
  619.     {
  620.         if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) &&
  621.              (((BundleTypePtr)ptrIterator)->count >= 0) )
  622.         {
  623.                 *returnBundleType = (BundleTypePtr)ptrIterator;
  624.                 error = noErr;
  625.         }
  626.         else
  627.         {
  628.             ptrIterator += ( sizeof(OSType) +
  629.                              sizeof(short) +
  630.                              ( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) );
  631.             ++index;
  632.         }
  633.     }
  634.         
  635.     return ( error );
  636. }
  637.  
  638. /*****************************************************************************/
  639.  
  640. /*
  641. **    GetLocalIDFromFREF
  642. **
  643. **    Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource
  644. **    looking for a matching fileType. If a matching fileType is found, return
  645. **    its icon local ID. If no match is found, return afpItemNotFound as the
  646. **    function result.
  647. */
  648. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  649.                                    OSType fileType,
  650.                                    short *iconLocalID)
  651. {
  652.     OSErr            error;
  653.     short            index;
  654.     IDRecPtr        idIterator;
  655.     FREFRecHandle    theFref;
  656.     
  657.     error = afpItemNotFound;    /* default to not found */
  658.     
  659.     /* For each localID in this type, get the FREF resource looking for fileType */
  660.     index = 0;
  661.     idIterator = &theBundleType->idArray[0];
  662.     *iconLocalID = 0;
  663.     
  664.     while ( (index <= theBundleType->count) && (*iconLocalID == 0) )
  665.     {
  666.         theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID);
  667.         if ( theFref != NULL )
  668.         {
  669.             if ( (*theFref)->fileType == fileType )
  670.             {
  671.                 *iconLocalID = (*theFref)->iconID;
  672.                 error = noErr;
  673.             }
  674.         }
  675.         
  676.         ++idIterator;
  677.         ++index;
  678.     }
  679.     
  680.     return ( error );
  681. }
  682.  
  683. /*****************************************************************************/
  684.  
  685. /*
  686. **    GetIconRsrcIDFromLocalID
  687. **
  688. **    Given a pointer to a 'ICN#' BundleType record, look for the IDRec with
  689. **    the localID that matches iconLocalID. If a matching IDRec is found,
  690. **    return the IDRec's rsrcID field value. If no match is found, return
  691. **    afpItemNotFound as the function result.
  692. */
  693. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  694.                                          short iconLocalID,
  695.                                          short *iconRsrcID)
  696. {
  697.     OSErr        error;
  698.     short        index;
  699.     IDRecPtr    idIterator;
  700.     
  701.     error = afpItemNotFound;    /* default to not found */
  702.     
  703.     /* Find the rsrcID of the icon family type, given the localID */
  704.     index = 0;
  705.     idIterator = &theBundleType->idArray[0];
  706.     *iconRsrcID = 0;
  707.     
  708.     while ( (index <= theBundleType->count) && (*iconRsrcID == 0) )
  709.     {
  710.         if ( idIterator->localID == iconLocalID )
  711.         {
  712.             *iconRsrcID = idIterator->rsrcID;
  713.             error = noErr;
  714.         }
  715.         
  716.         idIterator ++;
  717.         index ++;
  718.     }
  719.     
  720.     return ( error );
  721. }
  722.  
  723. /*****************************************************************************/
  724.  
  725. /*
  726. **    DTIconToResIcon
  727. **
  728. **    Map a Desktop Manager icon type to the corresponding resource type.
  729. **    Return (OSType)0 if there is no corresponding resource type.
  730. */
  731. static    OSType    DTIconToResIcon(short iconType)
  732. {
  733.     OSType    resType;
  734.     
  735.     switch ( iconType )
  736.     {
  737.         case kLargeIcon:
  738.             resType = large1BitMask;
  739.             break;
  740.         case kLarge4BitIcon:
  741.             resType = large4BitData;
  742.             break;
  743.         case kLarge8BitIcon:
  744.             resType = large8BitData;
  745.             break;
  746.         case kSmallIcon:
  747.             resType = small1BitMask;
  748.             break;
  749.         case kSmall4BitIcon:
  750.             resType = small4BitData;
  751.             break;
  752.         case kSmall8BitIcon:
  753.             resType = small8BitData;
  754.             break;
  755.         default:
  756.             resType = (OSType)0;
  757.             break;
  758.     }
  759.     
  760.     return ( resType );
  761. }
  762.  
  763. /*****************************************************************************/
  764.  
  765. /*
  766. **    GetIconFromDesktopFile
  767. **
  768. **    INPUT a pointer to a non-existent Handle, because we'll allocate one
  769. **
  770. **    search each BNDL resource for the right fileCreator and once we get it
  771. **        find the 'FREF' type in BNDL
  772. **        for each localID in the type, open the FREF resource
  773. **            if the FREF is the desired fileType
  774. **                get its icon localID
  775. **                get the ICN# type in BNDL
  776. **                get the icon resource number from the icon localID
  777. **                get the icon resource type from the desktop mgr's iconType
  778. **                get the icon of that type and number
  779. */
  780. static    OSErr    GetIconFromDesktopFile(ConstStr255Param volName,
  781.                                        short vRefNum,
  782.                                        short iconType,
  783.                                        OSType fileCreator,
  784.                                        OSType fileType,
  785.                                        Handle *iconHandle)
  786. {
  787.     OSErr            error;
  788.     short            realVRefNum;
  789.     Str255            desktopName;
  790.     short            savedResFile;
  791.     short            dfRefNum;
  792.     BNDLRecHandle    theBndl = NULL;
  793.     BundleTypePtr    theBundleType;
  794.     short            iconLocalID;
  795.     short            iconRsrcID;
  796.     OSType            iconRsrcType;
  797.     Handle            returnIconHandle;    
  798.     char            bndlState;
  799.     
  800.     *iconHandle = NULL;
  801.     
  802.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  803.     if ( error == noErr )
  804.     {
  805.         error = GetDesktopFileName(realVRefNum, desktopName);
  806.         if ( error == noErr )
  807.         {
  808.             savedResFile = CurResFile();
  809.         
  810.             /*
  811.             **    Open the 'Desktop' file in the root directory. (because
  812.             **    opening the resource file could preload unwanted resources,
  813.             **    bracket the call with SetResLoad(s))
  814.             */
  815.             SetResLoad(false);
  816.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  817.             SetResLoad(true);
  818.         
  819.             if ( dfRefNum != -1 )
  820.             {
  821.                 /*
  822.                 **    Find the BNDL resource with the specified creator.
  823.                 */
  824.                 error = FindBundleGivenCreator(fileCreator, &theBndl);
  825.                 if ( error == noErr )
  826.                 {
  827.                     /* Lock the BNDL resource so it won't be purged when other resources are loaded */
  828.                     bndlState = HGetState((Handle)theBndl);
  829.                     HLock((Handle)theBndl);
  830.                     
  831.                     /* Find the 'FREF' BundleType record in the BNDL resource. */
  832.                     error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
  833.                     if ( error == noErr )
  834.                     {
  835.                         /* Find the local ID in the 'FREF' resource with the specified fileType */
  836.                         error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
  837.                         if ( error == noErr )
  838.                         {
  839.                             /* Find the 'ICN#' BundleType record in the BNDL resource. */
  840.                             error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
  841.                             if ( error == noErr )
  842.                             {
  843.                                 /* Find the icon's resource ID in the 'ICN#' BundleType record */
  844.                                 error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
  845.                                 if ( error == noErr )
  846.                                 {
  847.                                     /* Map Desktop Manager icon type to resource type */
  848.                                     iconRsrcType = DTIconToResIcon(iconType);
  849.                                     
  850.                                     if ( iconRsrcType != (OSType)0 )
  851.                                     {
  852.                                         /* Load the icon */
  853.                                         returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
  854.                                         if ( returnIconHandle != NULL )
  855.                                         {
  856.                                             /* Copy the resource handle, and return the copy */
  857.                                             HandToHand(&returnIconHandle);
  858.                                             if ( MemError() == noErr )
  859.                                             {
  860.                                                 *iconHandle = returnIconHandle;
  861.                                             }
  862.                                             else
  863.                                             {
  864.                                                 error = afpItemNotFound;
  865.                                             }
  866.                                         }
  867.                                         else
  868.                                         {
  869.                                             error = afpItemNotFound;
  870.                                         }
  871.                                     }
  872.                                 }
  873.                             }
  874.                         }
  875.                     }
  876.                     /* Restore the state of the BNDL resource */ 
  877.                     HSetState((Handle)theBndl, bndlState);
  878.                 }
  879.                 /* Restore the resource chain and close the Desktop file */
  880.                 UseResFile(savedResFile);
  881.                 CloseResFile(dfRefNum);
  882.             }
  883.             else
  884.             {
  885.                 error = ResError(); /* could not open Desktop file */
  886.             }
  887.         }
  888.         if ( (error != noErr) && (error != memFullErr) )
  889.         {
  890.             error = afpItemNotFound;    /* force an error we should return */
  891.         }
  892.     }
  893.     
  894.     return ( error );
  895. }
  896.  
  897. /*****************************************************************************/
  898.  
  899. pascal    OSErr    DTGetIcon(ConstStr255Param volName,
  900.                           short vRefNum,
  901.                           short iconType,
  902.                           OSType fileCreator,
  903.                           OSType fileType,
  904.                           Handle *iconHandle)
  905. {
  906.     OSErr error;
  907.     DTPBRec pb;
  908.     short dtRefNum;
  909.     Boolean newDTDatabase;
  910.     Size bufferSize;
  911.     
  912.     *iconHandle = NULL;
  913.     error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  914.     if ( error == noErr )
  915.     {
  916.         /* there was a desktop database and it's now open */
  917.         
  918.         if ( !newDTDatabase )    /* don't bother to look in a new (empty) database */
  919.         {
  920.             /* get the buffer size for the requested icon type */
  921.             switch ( iconType )
  922.             {
  923.                 case kLargeIcon:
  924.                     bufferSize = kLargeIconSize;
  925.                     break;
  926.                 case kLarge4BitIcon:
  927.                     bufferSize = kLarge4BitIconSize;
  928.                     break;
  929.                 case kLarge8BitIcon:
  930.                     bufferSize = kLarge8BitIconSize;
  931.                     break;
  932.                 case kSmallIcon:
  933.                     bufferSize = kSmallIconSize;
  934.                     break;
  935.                 case kSmall4BitIcon:
  936.                     bufferSize = kSmall4BitIconSize;
  937.                     break;
  938.                 case kSmall8BitIcon:
  939.                     bufferSize = kSmall8BitIconSize;
  940.                     break;
  941.                 default:
  942.                     iconType = 0;
  943.                     bufferSize = 0;
  944.                     break;
  945.             }
  946.             if ( bufferSize != 0 )
  947.             {
  948.                 *iconHandle = NewHandle(bufferSize);
  949.                 if ( *iconHandle != NULL )
  950.                 {
  951.                     HLock(*iconHandle);
  952.         
  953.                     pb.ioDTRefNum = dtRefNum;
  954.                     pb.ioTagInfo = 0;
  955.                     pb.ioDTBuffer = **iconHandle;
  956.                     pb.ioDTReqCount = bufferSize;
  957.                     pb.ioIconType = iconType;
  958.                     pb.ioFileCreator = fileCreator;
  959.                     pb.ioFileType = fileType;
  960.                     error = PBDTGetIconSync(&pb);
  961.     
  962.                     HUnlock(*iconHandle);
  963.                     
  964.                     if ( error != noErr )
  965.                     {
  966.                         DisposeHandle(*iconHandle);    /* dispose of the allocated memory */
  967.                         *iconHandle = NULL;
  968.                     }
  969.                 }
  970.                 else
  971.                 {
  972.                     error = memFullErr;    /* handle could not be allocated */
  973.                 }
  974.             }
  975.             else
  976.             {
  977.                 error = paramErr;    /* unknown icon type requested */
  978.             }
  979.         }
  980.         else
  981.         {
  982.             error = afpItemNotFound;    /* the desktop database was empty - nothing to return */
  983.         }
  984.     }
  985.     else
  986.     {
  987.         /* There is no desktop database - try the Desktop file */
  988.         
  989.         error = GetIconFromDesktopFile(volName, vRefNum, iconType,
  990.                                         fileCreator, fileType, iconHandle);
  991.     }
  992.     
  993.     return ( error );
  994. }
  995.  
  996. /*****************************************************************************/
  997.  
  998. pascal    OSErr    DTSetComment(short vRefNum,
  999.                              long dirID,
  1000.                              ConstStr255Param name,
  1001.                              ConstStr255Param comment)
  1002. {
  1003.     DTPBRec pb;
  1004.     OSErr error;
  1005.     short dtRefNum;
  1006.     Boolean newDTDatabase;
  1007.  
  1008.     error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  1009.     if ( error == noErr )
  1010.     {
  1011.         pb.ioDTRefNum = dtRefNum;
  1012.         pb.ioNamePtr = (StringPtr)name;
  1013.         pb.ioDirID = dirID;
  1014.         pb.ioDTBuffer = (Ptr)&comment[1];
  1015.         /* Truncate the comment to 200 characters just in case */
  1016.         /* some file system doesn't range check */
  1017.         if ( comment[0] <= 200 )
  1018.         {
  1019.             pb.ioDTReqCount = comment[0];
  1020.         }
  1021.         else
  1022.         {
  1023.             pb.ioDTReqCount = 200;
  1024.         }
  1025.         error = PBDTSetCommentSync(&pb);
  1026.     }
  1027.     return (error);
  1028. }
  1029.  
  1030. /*****************************************************************************/
  1031.  
  1032. pascal    OSErr    FSpDTSetComment(const FSSpec *spec,
  1033.                               ConstStr255Param comment)
  1034. {
  1035.     return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
  1036. }
  1037.  
  1038. /*****************************************************************************/
  1039.  
  1040. /*
  1041. **    GetCommentID
  1042. **
  1043. **    Get the comment ID number for the Desktop file's 'FCMT' resource ID from
  1044. **    the file or folders fdComment (frComment) field.
  1045. */
  1046. static    OSErr    GetCommentID(short vRefNum,
  1047.                              long dirID,
  1048.                              ConstStr255Param name,
  1049.                              short *commentID)
  1050. {
  1051.     CInfoPBRec pb;
  1052.     OSErr error;
  1053.  
  1054.     error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
  1055.     *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
  1056.     return ( error );
  1057. }
  1058.  
  1059. /*****************************************************************************/
  1060.  
  1061. /*
  1062. **    GetCommentFromDesktopFile
  1063. **
  1064. **    Get a file or directory's Finder comment field (if any) from the
  1065. **    Desktop file's 'FCMT' resources.
  1066. */
  1067. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  1068.                                           long dirID,
  1069.                                           ConstStr255Param name,
  1070.                                           Str255 comment)
  1071. {
  1072.     OSErr error;
  1073.     short commentID;
  1074.     short realVRefNum;
  1075.     Str255 desktopName;
  1076.     short savedResFile;
  1077.     short dfRefNum;
  1078.     StringHandle commentHandle;
  1079.     
  1080.     /* Get the comment ID number */
  1081.     error = GetCommentID(vRefNum, dirID, name, &commentID);
  1082.     if ( error == noErr )
  1083.     {
  1084.         if ( commentID != 0 )    /* commentID == 0 means there's no comment */
  1085.         {
  1086.             error = DetermineVRefNum(name, vRefNum, &realVRefNum);
  1087.             if ( error == noErr )
  1088.             {
  1089.                 error = GetDesktopFileName(realVRefNum, desktopName);
  1090.                 if ( error == noErr )
  1091.                 {
  1092.                     savedResFile = CurResFile();
  1093.                     /*
  1094.                     **    Open the 'Desktop' file in the root directory. (because
  1095.                     **    opening the resource file could preload unwanted resources,
  1096.                     **    bracket the call with SetResLoad(s))
  1097.                     */
  1098.                     SetResLoad(false);
  1099.                     dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  1100.                     SetResLoad(true);
  1101.                     
  1102.                     if ( dfRefNum != -1)
  1103.                     {
  1104.                         /* Get the comment resource */
  1105.                         commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
  1106.                         if ( commentHandle != NULL )
  1107.                         {
  1108.                             if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
  1109.                             {
  1110.                                 BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
  1111.                             }
  1112.                             else
  1113.                             {
  1114.                                 error = afpItemNotFound;    /* no comment available */
  1115.                             }
  1116.                         }
  1117.                         else
  1118.                         {
  1119.                             error = afpItemNotFound;    /* no comment available */
  1120.                         }
  1121.                         
  1122.                         /* restore the resource chain and close the Desktop file */
  1123.                         UseResFile(savedResFile);
  1124.                         CloseResFile(dfRefNum);
  1125.                     }
  1126.                     else
  1127.                     {
  1128.                         error = afpItemNotFound;
  1129.                     }
  1130.                 }
  1131.                 else
  1132.                 {
  1133.                     error = afpItemNotFound;
  1134.                 }
  1135.             }
  1136.         }
  1137.         else
  1138.         {
  1139.             error = afpItemNotFound;    /* no comment available */
  1140.         }
  1141.     }
  1142.     
  1143.     return ( error );
  1144. }
  1145.  
  1146. /*****************************************************************************/
  1147.  
  1148. pascal    OSErr    DTGetComment(short vRefNum,
  1149.                              long dirID,
  1150.                              ConstStr255Param name,
  1151.                              Str255 comment)
  1152. {
  1153.     DTPBRec pb;
  1154.     OSErr error;
  1155.     short dtRefNum;
  1156.     Boolean newDTDatabase;
  1157.  
  1158.     if (comment != NULL)
  1159.     {
  1160.         comment[0] = 0;    /* return nothing by default */
  1161.         
  1162.         /* attempt to open the desktop database */
  1163.         error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  1164.         if ( error == noErr )
  1165.         {
  1166.             /* There was a desktop database and it's now open */
  1167.             
  1168.             if ( !newDTDatabase )
  1169.             {
  1170.                 pb.ioDTRefNum = dtRefNum;
  1171.                 pb.ioNamePtr = (StringPtr)name;
  1172.                 pb.ioDirID = dirID;
  1173.                 pb.ioDTBuffer = (Ptr)&comment[1];
  1174.                 /*
  1175.                 **    IMPORTANT NOTE #1: Inside Macintosh says that comments
  1176.                 **    are up to 200 characters. While that may be correct for
  1177.                 **    the HFS file system's Desktop Manager, other file
  1178.                 **    systems (such as Apple Photo Access) return up to
  1179.                 **    255 characters. Make sure the comment buffer is a Str255
  1180.                 **    or you'll regret it.
  1181.                 **
  1182.                 **    IMPORTANT NOTE #2: Although Inside Macintosh doesn't
  1183.                 **    mention it, ioDTReqCount is a input field to
  1184.                 **    PBDTGetCommentSync. Some file systems (like HFS) ignore
  1185.                 **    ioDTReqCount and always return the full comment --
  1186.                 **    others (like AppleShare) respect ioDTReqCount and only
  1187.                 **    return up to ioDTReqCount characters of the comment.
  1188.                 */
  1189.                 pb.ioDTReqCount = sizeof(Str255) - 1;
  1190.                 error = PBDTGetCommentSync(&pb);
  1191.                 if (error == noErr)
  1192.                 {
  1193.                     comment[0] = (unsigned char)pb.ioDTActCount;
  1194.                 }
  1195.             }
  1196.         }
  1197.         else
  1198.         {
  1199.             /* There is no desktop database - try the Desktop file */
  1200.             error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
  1201.             if ( error != noErr )
  1202.             {
  1203.                 error = afpItemNotFound;    /* return an expected error */
  1204.             }
  1205.         }
  1206.     }
  1207.     else
  1208.     {
  1209.         error = paramErr;
  1210.     }
  1211.     
  1212.     return (error);
  1213. }
  1214.  
  1215. /*****************************************************************************/
  1216.  
  1217. pascal    OSErr    FSpDTGetComment(const FSSpec *spec,
  1218.                               Str255 comment)
  1219. {
  1220.     return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
  1221. }
  1222.  
  1223. /*****************************************************************************/
  1224.  
  1225. pascal    OSErr    DTCopyComment(short srcVRefNum,
  1226.                               long srcDirID,
  1227.                               ConstStr255Param srcName,
  1228.                               short dstVRefNum,
  1229.                               long dstDirID,
  1230.                               ConstStr255Param dstName)
  1231. /* The destination volume must support the Desktop Manager for this to work */
  1232. {
  1233.     OSErr error;
  1234.     Str255 comment;
  1235.  
  1236.     error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
  1237.     if ( (error == noErr) && (comment[0] > 0) )
  1238.     {
  1239.         error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
  1240.     }
  1241.     return (error);
  1242. }
  1243.  
  1244. /*****************************************************************************/
  1245.  
  1246. pascal    OSErr    FSpDTCopyComment(const FSSpec *srcSpec,
  1247.                                const FSSpec *dstSpec)
  1248. /* The destination volume must support the Desktop Manager for this to work */
  1249. {
  1250.     return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
  1251.                         dstSpec->vRefNum, dstSpec->parID, dstSpec->name));
  1252. }
  1253.  
  1254. /*****************************************************************************/
  1255.